package com.example.myapplication.widgets.chart;

import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.DashPathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

import com.example.myapplication.R;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

/**
 * 柱状图
 */
public class HistogramView extends View {

    private int mWidth, mHeight;

    // region UI属性，间距颜色等
    // -------自定义可修改属性------------
    private int mStrokeWidth = 2; // 坐标轴线宽
    private int mDashStrokeWidth = 2; // 虚线线宽
    private int mAxisTxtSize = 39;//坐标轴字体大小
    private int mHistogramWidth = 30;// 柱状的宽度
    private int mAxisXLastSpace = 100;// X轴最后一个刻度离末尾的空白距离
    private int mAxisYLastSpace = 50;// Y轴最后一个刻度离末尾的空白距离
    private int mAxisYLeftMinWidth = 0;// Y轴到左边的最小距离
    private int mAxisTxtSpace = 20;// 坐标轴与文字的间距
    private int mAxisTitleSpace = 20;// 坐标轴与标题的间距
    private int mDashEffect = 6;// 虚线的线长
    private int mDashEffectSpace = 12;// 虚线的间隔

    private int mAxisColor = Color.LTGRAY;
    private int mAxisTxtColor = Color.BLACK;
    private int mDashLineColor = Color.LTGRAY;
    private int mHistogramColor = Color.GREEN;

    // -------非自定义，计算得到的属性---------
    private float mXIntervalSize;// X轴两个刻度之间的间距
    private float mYIntervalSize;// Y轴两个刻度之间的间距
    private float mAxisY_XPoi;// Y轴的X位置
    private float mAxisX_YPoi;// X轴的Y位置
    // endregion

    private Paint mPaint;
    private Path mPath;
    // 绘制虚线:
    private Paint mDashPaint;

    private String mAxisXTitle, mAxisYTitle; // XY轴末尾的标题
    private final List<String> mAxisXTxt = new ArrayList<>();
    private final List<Float> mAxisYTxt = new ArrayList<>();
    private float mAxisYIntervalValue; // Y轴两个刻度值的差
    private final float mAxisXTitleMultiLineInterval = 6; // X轴多行标题时，每行标题的间距

    private boolean isJustDrawCenterAxisX; // 仅绘制中间的x轴坐标值

    private final List<HistogramBean> data = new ArrayList<>();

    public HistogramView(Context context) {
        super(context);
        init(context, null);
    }

    public HistogramView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context, attrs);
    }

    public HistogramView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    public HistogramView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    private void init(Context context, @Nullable AttributeSet attrs) {
        if (attrs != null) {
            TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.HistogramView);
            mStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_stroke_width, mStrokeWidth);
            mDashStrokeWidth = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_stroke_width, mDashStrokeWidth);
            mAxisTxtSize = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_axis_text_size, mAxisTxtSize);
            mHistogramWidth = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_histogram_width, mHistogramWidth);
            mAxisXLastSpace = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_axis_x_last_space, mAxisXLastSpace);
            mAxisYLastSpace = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_axis_y_last_space, mAxisXLastSpace);
            mAxisYLeftMinWidth = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_axis_y_left_min_width, mAxisYLeftMinWidth);
            mAxisTxtSpace = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_axis_text_space, mAxisTxtSpace);
            mAxisTitleSpace = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_axis_title_space, mAxisTitleSpace);
            mDashEffect = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_dash_effect, mDashEffect);
            mDashEffectSpace = typedArray.getDimensionPixelSize(R.styleable.HistogramView_hv_chart_dash_effect_space, mDashEffectSpace);

            mAxisColor = typedArray.getColor(R.styleable.HistogramView_hv_chart_axis_color, mAxisColor);
            mAxisTxtColor = typedArray.getColor(R.styleable.HistogramView_hv_chart_axis_text_color, mAxisTxtColor);
            mDashLineColor = typedArray.getColor(R.styleable.HistogramView_hv_chart_dash_line_color, mAxisColor);
            mHistogramColor = typedArray.getColor(R.styleable.HistogramView_hv_chart_histogram_color, mHistogramColor);
            typedArray.recycle();
        }

        mPath = new Path();

        mPaint = new Paint();
        mPaint.setColor(mAxisColor);
        mPaint.setAntiAlias(true);
        mPaint.setTextAlign(Paint.Align.CENTER);
        mPaint.setStrokeWidth(mStrokeWidth);
        mPaint.setTextSize(mAxisTxtSize);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);

        mDashPaint = new Paint();
        mDashPaint.setColor(mDashLineColor);
        mDashPaint.setAntiAlias(true);
        mDashPaint.setStrokeWidth(mDashStrokeWidth);
        mDashPaint.setStyle(Paint.Style.STROKE);
        // 绘制虚线
        mDashPaint.setPathEffect(new DashPathEffect(new float[]{mDashEffect, mDashEffectSpace}, 0));
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        mWidth = getWidth() - getPaddingEnd();
        mHeight = getHeight();

        calculateInfo();
    }

    public void setAxisInfo(List<String> axisXTxt) {
        setAxisInfo(axisXTxt, "", "");
    }

    public void setAxisInfo(List<String> axisXTxt, String axisXTitle, String axisYTitle) {
        setAxisInfo(axisXTxt, null, axisXTitle, axisYTitle);
    }

    public void setAxisInfo(List<String> axisXTxt, List<Float> axisYTxt) {
        setAxisInfo(axisXTxt, axisYTxt, "", "");
    }

    public void setAxisInfo(List<String> axisXTxt, List<Float> axisYTxt, String axisXTitle, String axisYTitle) {
        mAxisXTxt.clear();
        mAxisYTxt.clear();
        mAxisXTxt.addAll(axisXTxt);
        if (axisYTxt != null && !axisYTxt.isEmpty()) {
            mAxisYTxt.addAll(axisYTxt);
            mAxisYIntervalValue = axisYTxt.get(0);
        } else {
            for (int i = 0; i < 5; i++) {
                mAxisYTxt.add((float) (i + 1));
            }
            mAxisYIntervalValue = 1;
        }
        mAxisXTitle = axisXTitle;
        mAxisYTitle = axisYTitle;
    }

    // 使用动画，并且y轴刻度值
    public void clear(){
        isJustDrawCenterAxisX = false;
        data.clear();
        invalidate();
    }

    public void setHistogramWidth(int histogramWidth) {
        mHistogramWidth = histogramWidth;
    }

    public void setJustDrawCenterAxisX(boolean justDrawCenterAxisX) {
        isJustDrawCenterAxisX = justDrawCenterAxisX;
    }

    public void setData(List<HistogramBean> data) {
        setData(data, 0);
    }

    public void setData(List<HistogramBean> data, int axisYCount) {
        this.data.clear();
        this.data.addAll(data);
        if (axisYCount > 0)
            refreshAxisYValue(data, axisYCount);
        calculateInfo();
    }

    public void setDataWithAnim(List<HistogramBean> data) {
        setDataWithAnim(data, 0);
    }

    public void setDataWithAnim(List<HistogramBean> data, int axisYCount) {
        if (axisYCount > 0)
            refreshAxisYValue(data, axisYCount);
        List<HistogramBean> preList = new ArrayList<>(this.data);
        int duration = 300;
        ValueAnimator animator = ObjectAnimator.ofInt(0, duration).setDuration(duration);
        animator.addUpdateListener(animation -> {
            int preValue;
            int addValue;
            HistogramBean bean;
            HistogramView.this.data.clear();
            for (int i = 0; i < data.size(); i++) {
                if (i < preList.size())
                    preValue = preList.get(i).axisY;
                else
                    preValue = 0;

                addValue = (data.get(i).axisY - preValue) * (int) animation.getAnimatedValue() / duration;
                bean = new HistogramBean();
                bean.axisX = data.get(i).axisX;
                bean.axisY = preValue + addValue;
                HistogramView.this.data.add(bean);
            }
            calculateInfo();
        });
        animator.start();
    }

    private void refreshAxisYValue(List<HistogramBean> data, int axisYCount) {
        // 根据value的值去计算纵坐标的数值
        float maxValue = 0;
        for (HistogramBean bean : data) {
            maxValue = Math.max(maxValue, bean.axisY);
        }
        float gridValue = 1;
        while ((maxValue /= 10f) > 1) {
            gridValue *= 10;
        }
        if (maxValue >= 0.5)
            gridValue *= 2;
        // 给纵坐标的数值赋值
        mAxisYTxt.clear();
        for (int i = 1; i <= axisYCount; i++) {
            mAxisYTxt.add(i * gridValue);
        }
        mAxisYIntervalValue = mAxisYTxt.get(0);
    }

    private void calculateInfo() {
        mPath.reset();
        if (mAxisXTxt.isEmpty() || mAxisYTxt.isEmpty()) return;

        String axisX = mAxisXTxt.get(0);
        String[] split = axisX.split("\n");

        // 计算X轴Y轴位置
        mAxisY_XPoi = 0;
        for (float txt : mAxisYTxt) {
            mAxisY_XPoi = Math.max(mAxisYLeftMinWidth, mPaint.measureText(String.valueOf(txt)) + mAxisTxtSpace);
        }
        mAxisX_YPoi = mHeight - mPaint.getTextSize() * split.length
                - mAxisXTitleMultiLineInterval * (split.length - 1) - mAxisTxtSpace;

        // 计算刻度间距
        float xTitleWidth = mPaint.measureText(mAxisXTitle);
        mXIntervalSize = (mWidth - mAxisY_XPoi - mAxisXLastSpace - xTitleWidth - mAxisTitleSpace) / mAxisXTxt.size();
        mYIntervalSize = (mAxisX_YPoi - mAxisYLastSpace - mPaint.getTextSize() - mAxisTitleSpace) / mAxisYTxt.size();

        mPath.moveTo(mAxisY_XPoi, mAxisX_YPoi);
        mPath.lineTo(mWidth - xTitleWidth - mAxisTitleSpace, mAxisX_YPoi);

        mPath.moveTo(mAxisY_XPoi, mAxisX_YPoi);
        mPath.lineTo(mAxisY_XPoi, mPaint.getTextSize() + mAxisTitleSpace);
        invalidate();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // 绘制坐标轴
        drawAxis(canvas);
        // 绘制刻度和虚线
        drawAxisTxtAndLine(canvas);
        // 绘制数据柱状
        drawData(canvas);
    }

    private void drawAxis(Canvas canvas) {
        mPaint.setColor(mAxisColor);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.drawPath(mPath, mPaint);
    }

    private void drawAxisTxtAndLine(Canvas canvas) {
        // 绘制刻度
        mPaint.setColor(mAxisTxtColor);
        mPaint.setStyle(Paint.Style.FILL);

        // x轴刻度
        String[] split = mAxisXTxt.get(0).split("\n");
        if (isJustDrawCenterAxisX) {
            drawAxisXTitle(canvas, 0);

            int center;
            if (mAxisXTxt.size() >= 28)
                center = 15;
            else
                center = (int) (mAxisXTxt.size() / 2);
            drawAxisXTitle(canvas, center - 1);

            drawAxisXTitle(canvas, mAxisXTxt.size() - 1);
        } else {
            for (int i = 0; i < mAxisXTxt.size(); i++) {
                drawAxisXTitle(canvas, i);
            }
        }

        // y轴刻度
        canvas.drawText("0", mAxisY_XPoi - mAxisTxtSpace - mPaint.measureText("0") / 2f,
                mAxisX_YPoi + mPaint.getTextSize() / 3, mPaint);
        if (!mAxisYTxt.isEmpty()) {
            boolean changeToK = mAxisYTxt.get(0) >= 2000;
            float lastX = mWidth - mPaint.measureText(mAxisXTitle) - mAxisTitleSpace;
            float x, y;
            for (int i = 0; i < mAxisYTxt.size(); i++) {
                String text = changeToK ? String.format(Locale.getDefault(), "%dK", (int) (mAxisYTxt.get(i) / 1000))
                        : String.valueOf(mAxisYTxt.get(i).intValue());
                x = mAxisY_XPoi - mAxisTxtSpace - mPaint.measureText(text) / 2f;
                y = mAxisX_YPoi - (i + 1) * mYIntervalSize;
                mPaint.setStyle(Paint.Style.FILL);
                canvas.drawText(text, x, y + mPaint.getTextSize() / 3, mPaint);

                mPaint.setStyle(Paint.Style.STROKE);
                canvas.drawLine(mAxisY_XPoi, y, lastX, y, mDashPaint);
            }
        }

        // 绘制标题
        mPaint.setStyle(Paint.Style.FILL);
        if (!TextUtils.isEmpty(mAxisXTitle))
            canvas.drawText(mAxisXTitle, mWidth - mPaint.measureText(mAxisXTitle) / 2, mAxisX_YPoi + mPaint.getTextSize() / 3, mPaint);
        if (!TextUtils.isEmpty(mAxisYTitle))
            canvas.drawText(mAxisYTitle, mAxisY_XPoi, mPaint.getTextSize(), mPaint);
    }

    private void drawAxisXTitle(Canvas canvas, int index) {
        float x = mAxisY_XPoi + (index + 0.5f) * mXIntervalSize;
        String[] split = mAxisXTxt.get(index).split("\n");
        if (split.length == 1)
            canvas.drawText(mAxisXTxt.get(index), x, mHeight - mPaint.getTextSize() * 0.18f, mPaint);
        else {
            for (int i = 0; i < split.length; i++) {
                canvas.drawText(split[i], x, mHeight - mPaint.getTextSize() * 0.18f
                        - (mPaint.getTextSize() + mAxisXTitleMultiLineInterval) * i, mPaint);
            }
        }
    }

    private void drawData(Canvas canvas) {
        mPaint.setColor(mHistogramColor);
        mPaint.setStyle(Paint.Style.FILL);
        float x;
        float y;
        for (int i = 0; i < mAxisXTxt.size(); i++) {
            String axisX = mAxisXTxt.get(i);
            for (HistogramBean datum : data) {
                if (datum.axisX.equals(axisX) && datum.axisY != 0) {
                    x = mAxisY_XPoi + (i + 0.5f) * mXIntervalSize;
                    y = mAxisX_YPoi;

                    float histogramHeight = mYIntervalSize * datum.axisY / mAxisYIntervalValue;
                    float left = x - mHistogramWidth / 2f;
                    float top = y - histogramHeight + mHistogramWidth / 2f;
                    if (top > y) {
                        // 顶部半圆超出了x轴
                        Path path = new Path();
                        path.moveTo(left, y);
                        path.cubicTo(left, y, left + mHistogramWidth / 2f, top - mHistogramWidth / 2f,
                                left + mHistogramWidth, y);
                        path.close();
                        canvas.drawPath(path, mPaint);
                    } else {
                        canvas.drawRect(left, top, left + mHistogramWidth, y, mPaint);
                        canvas.drawArc(left, top - mHistogramWidth / 2f, left + mHistogramWidth, top + mHistogramWidth / 2f,
                                180, 180, true, mPaint);
                    }
                    break;
                }
            }
        }
    }
}
